package me.yricky.alia.ui.layoutPage

import androidx.compose.foundation.*
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.material.Text
import androidx.compose.runtime.*
import androidx.compose.ui.ExperimentalComposeUiApi
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.drawBehind
import androidx.compose.ui.geometry.Offset
import androidx.compose.ui.geometry.Size
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.Path
import androidx.compose.ui.graphics.PathEffect
import androidx.compose.ui.graphics.drawscope.*
import androidx.compose.ui.input.pointer.*
import me.yricky.alia.data.base.Coord
import me.yricky.alia.data.shape.Box
import me.yricky.alia.data.shape.contains
import me.yricky.alia.ui.*
import me.yricky.alia.ui.layoutPage.renderModel.LayerRender
import java.awt.Cursor

/**
 * @author Yricky
 * @date 2022/1/30
 */
fun DrawScope.getBox(offset: Coord): FBox = FBox(
    Offset(offset.x - size.width/2,offset.y - size.height/2),
    Offset(offset.x + size.width/2,offset.y + size.height/2),
)

@OptIn(ExperimentalComposeUiApi::class, ExperimentalFoundationApi::class)
@Composable
fun CellCanvas(
    modifier: Modifier = Modifier,
    model:CellCanvasViewModel
){

    /**
     * Cursor location
     */
    var x by remember { mutableStateOf(0) }
    var y by remember { mutableStateOf(0) }

    var visibleLayers by remember { mutableStateOf(emptyList<LayerRender>()) }
    var canvasBox by remember { mutableStateOf(FBox(Offset(0f,0f), Offset(1f,1f))) }

    /**
     * 拖动时使用的临时变量
     */
    var tmpOffset by remember { mutableStateOf(Coord(0,0)) }
    var tmpX by remember { mutableStateOf(0) }
    var tmpY by remember { mutableStateOf(0) }

    var cxtMenuItems by remember { mutableStateOf(listOf<ContextMenuItem>()) }
    val contextMenuState = remember { ContextMenuState() }


    ContextMenuArea(items = {
        cxtMenuItems.also {
            if(it.isEmpty()){
                contextMenuState.status = ContextMenuState.Status.Closed
            }
        }
    }, state = contextMenuState){
        val offset by model.viewState.offset.collectAsState()
        val zoom by model.viewState.zoom.collectAsState()

        Box(modifier
            .pointerHoverIcon(PointerIcon(Cursor.getPredefinedCursor(Cursor.CROSSHAIR_CURSOR)))
            .drawBehind {
                canvasBox = getBox(offset)
            }
            .pointerEvent(PointerEventType.Press){ pe->
                if(pe.buttons.isTertiaryPressed){
                    pe.changes.lastOrNull()?.position?.let {
                        val pCoord = it.invertRelativeVertex(canvasBox.width,canvasBox.height,zoom,offset.toOffset())
                        tmpX = pCoord.x
                        tmpY = pCoord.y
                        tmpOffset = offset
                    }
                }else if(pe.buttons.isSecondaryPressed){
                    val cursorCoord = Coord(x,y)
//                    cxtMenuItems = visibleLayers.flatMap {
//                        val list = ArrayList<ContextMenuItem>()
//                        val renderUnits = it.renderUnits.value
//                        renderUnits.forEach { ru->
//                            ru.second.texts.forEach { t->
//                                if(t.contains(cursorCoord)){
//                                    list.add(ContextMenuItem("Text(\"${t.txt}\",${t.coord}) at ${it.layerId.value}"){})
//                                }
//                            }
//                            ru.second.shapes.forEach { sh ->
//                                if(sh.contains(cursorCoord)){
//                                    val str = if(sh is Box){
//                                        sh.toString()
//                                    }else{
//                                        "shape(${sh.vertices.size}vertices)"
//                                    }
//                                    list.add(ContextMenuItem("$str at ${it.layerId.value}"){})
//                                }
//                            }
//                        }
//                        list
//                    }
                }
            }
            .pointerEvent(PointerEventType.Move){ pe->
                pe.changes.lastOrNull()?.position?.let{
                    if(pe.buttons.isTertiaryPressed){
                        model.setOffset(
                            it.invertRelativeVertex(canvasBox.width,canvasBox.height,zoom,tmpOffset.toOffset())
                                .let{
                                    Coord(
                                        tmpOffset.x - (it.x-tmpX),
                                        tmpOffset.y - (it.y-tmpY)
                                    )
                                }
                        )
                    }else{
                        it.invertRelativeVertex(canvasBox.width,canvasBox.height,zoom,offset.toOffset()).let{
                                x = it.x
                                y = it.y
                            }
                    }
                }


            }
            .pointerEvent(PointerEventType.Scroll){
                it.changes.lastOrNull()?.scrollDelta?.let {
                    model.setZoom(if(it.y < 0){ zoom*1.25f }else { zoom*0.8f })
                }
            }
        ){
            val dotStroke by remember { mutableStateOf(Stroke(
                pathEffect = PathEffect.dashPathEffect(floatArrayOf(1f, 2f, 4f, 8f), 1f)
            )) }
            val layers = model.layerRenders
            val invisibleLayer by model.viewState.invisibleLayer.collectAsState()
            visibleLayers = layers.filter { !invisibleLayer.value.contains(it.layerId) }
            visibleLayers.forEach { layer ->
                LayerCanvas(layer,offset.toOffset(),zoom)
            }
            val showDots by model.viewState.showGridDots.collectAsState()
            Canvas(modifier.fillMaxSize()){
                drawPath(
                    Path().apply {
                        model.viewState.cellBBox.value
                            .relativeVertices(canvasBox.width,canvasBox.height,zoom,offset.toOffset())
                            .also { moveTo(it[0].x, it[0].y) }
                            .forEach { lineTo(it.x, it.y) }
                    }, Color.Black, 0.5f, dotStroke
                )
                if(showDots){
                    useCoordDots(canvasBox, zoom){
                        drawCircle(
                            Color.Gray,
                            1.5f,
                            it,
                        )
                    }
                }
            }
            Column {
                Text("x:$x,y:$y")
                Text("$offset")
            }
        }
    }
}



@Composable
private fun LayerCanvas(model: LayerRender,offset: Offset,zoom:Float){
    val style = model.style
    val renderUnits = model.renderUnits

    var canvasSize by remember { mutableStateOf(Size(1f,1f)) }
    Box(Modifier
        .fillMaxSize()
        .drawBehind {
            canvasSize = size
            val fillPaint = style.fillPaint(size)
            val strokePaint = style.strokePaint()
            val offX = -offset.x*zoom + size.width/2
            val offY = offset.y*zoom + size.height/2
            withTransform({
                scale(zoom, Offset(offX,offY))
//                translate(offX,offY)
            }){
                renderUnits.forEach {
                    withTransform({ transform(it.second.matrix) }){
                        it.second.texts.forEach {
                            val vertex = it.vertices[0].toOffset()
                            drawCircle(
                                style.color,
                                2f,
                                Offset(vertex.x,vertex.y),
                            )
                        }
                        it.second.shapePaths.forEach {
                            val path = Path().apply { addPath(it.second) }
                            drawContext.canvas.drawPath(path, fillPaint)
                            if(style.stroke){
                                drawContext.canvas.drawPath(path, strokePaint)
                            }
                        }
                    }
                }
            }
        }
    ) {
//        renderUnits.forEach {
//            val offset = model.offset.value
//            val zoom = model.zoom.value
//            it.second.texts.forEach {
//                Text(it.txt,Modifier.offset {
//                    val vertex = it.vertices[0].relativeVertex(canvasSize.width, canvasSize.height,zoom,offset)
//                    IntOffset(
//                        (vertex.x).toInt(),
//                        (vertex.y).toInt()
//                    )
//                }.background(style.color), fontFamily = FontFamily.Serif)
//            }
//        }
    }
}